﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using NUnit.Framework;
using WB.Mvc.Forms;

namespace WB.Forms.Tests
{
	[TestFixture]
	public class Spike
	{
		[Test]
		public void SeeFormOutput()
		{
			ModelForm<Parent> modelForm = new ModelForm<Parent>(new Parent());
			string s = modelForm.AsDiv();
			Console.WriteLine(s);
		}

		[Test]
		public void PropertyInfo_Equals_Another_Instance_Of_Same_Property()
		{
			PropertyInfo one = typeof(Parent).GetProperties()[0];
			PropertyInfo two = typeof(Parent).GetProperties()[0];

			Assert.AreEqual(one, two);
		}

		[Test]
		public void PropertyDescriptor_Equals_Another_Instance_Of_Same_Property()
		{
			PropertyDescriptor one = TypeDescriptor.GetProperties(typeof(Parent))[0];
			PropertyDescriptor two = TypeDescriptor.GetProperties(typeof(Parent))[0];

			Assert.AreEqual(one, two);
		}

		[Test]
		public void TypeDescriptor_AddProvider()
		{
			TypeDescriptor.AddProvider(new ModelTypeDescriptionProvider<Parent>(TypeDescriptor.GetProvider(typeof(Parent))), typeof (Parent));

			var properties = TypeDescriptor.GetProperties(typeof (Parent));

			Assert.AreEqual(1, properties.Count);
			Assert.AreEqual("Name", properties[0].Name);

			Parent stub = new Parent();

			properties[0].SetValue(stub, "test");
		}

		protected class ModelTypeDescriptionProvider<TModel>: TypeDescriptionProvider
		{
			private ICollection<MemberInfo> memberList;

			public ModelTypeDescriptionProvider(TypeDescriptionProvider parent)
				: base(parent)
			{
				memberList = new HashSet<MemberInfo>();
			}

			public ModelTypeDescriptionProvider<TModel> Map<TReturn>(Expression<Func<TModel, TReturn>> member)
			{
				var lambda = member as LambdaExpression;
				if (lambda == null)
					throw new InvalidOperationException("Expected a lambda expression.");

				var body = lambda.Body;

				var memberExpression = body as MemberExpression;
				if (body == null)
					throw new InvalidOperationException("Expected member expression");

				MemberInfo memberInfo = memberExpression.Member;
				memberList.Add(memberInfo);

				return this;
			}

			public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
			{
				CustomDescriptor<Parent> descriptor = new CustomDescriptor<Parent>(base.GetTypeDescriptor(objectType, instance));
				foreach (MemberInfo memberInfo in memberList)
					descriptor.Map(memberInfo);
				return descriptor;
			}
		}

		protected class CustomDescriptor<T>: CustomTypeDescriptor
		{
			private ICollection<MemberInfo> memberList;
			private ICustomTypeDescriptor parent;

			public CustomDescriptor(ICustomTypeDescriptor parent): base(parent)
			{
				this.parent = parent;
				memberList = new HashSet<MemberInfo>();
			}

			public CustomDescriptor<T> Map(MemberInfo memberInfo)
			{
				memberList.Add(memberInfo);
				return this;
			}

			public override PropertyDescriptorCollection GetProperties()
			{
				var propertyDescriptors = parent.GetProperties();

				return new PropertyDescriptorCollection(
					(from desc in propertyDescriptors.Cast<PropertyDescriptor>()
					 from member in memberList
					 where desc.Name.Equals(member.Name, StringComparison.InvariantCulture)
					 select desc).ToArray()
				);
			}
		}

		protected class Parent
		{
			public Parent()
			{
				Child = new Child();
			}

			public int Id { get { return 1; } }

			public string Name { get; set; }

			public bool IsActive { get; set; }

			public int Age { get; set; }

			public Child Child { get; set; }
		}

		protected class Child
		{
			public string Name { get; set; }

			public Size Size { get; set; }
		}

		protected enum Size
		{
			Small,
			Medium,
			Large
		}
	}
}
